home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 014a / snip23.zip / SNIPPR23.ASM next >
Assembly Source File  |  1990-12-01  |  29KB  |  849 lines

  1. ; SNIPPER is a resident utility which allows cutting out a portion
  2. ; of the screen.  The selected portion may be printed, written
  3. ; to disk or entered in the keyboard buffer.  Activate SNIPPER by
  4. ; pressing ALT-W, then position the cursor in the upper left corner of
  5. ; the window using the cursor pad keys,(i.e.,arrows plus Home, End, PgUp
  6. ; and PgDn).  Press CR to fix the first corner,
  7. ; then expand the window with arrow keys.  Finally, type "P" to print,
  8. ; "F" for disk file, "G" to retrieve or CR for a help menu.  Press ESC
  9. ; any time to exit SNIPPER.  When installing SNIPPER, use the optional
  10. ; parameters to expand it's internal buffer for displays (such as the
  11. ; EGA) containing more than the standard 25 rows and 80 columns.
  12. ;   SNIPPER  [rows,columns]
  13.  
  14. ; Version 1.0 - as published.
  15. ; Version 1.1 - corrects a bug in the INT 21 interrupt routine.
  16. ; Version 1.2 - runs correctly on the AT&T 6300
  17. ; Version 2.2 - "r" function added by J. Turner (lines 75, 167-169, 186, 188,
  18. ;            & lines 198-9)
  19. ; Version 2.3 - Cursor Pad Keys(Home,End,PgUp,PgDn) added by T.Gentile
  20. ;        New & Modified Lines have V2.3 Suffix in Columns 75-78
  21. ;------------------------------------;
  22. ; BIOS_SEG IS THE ROM-BIOS DATA AREA ;
  23. ;------------------------------------;
  24. BIOS_SEG    SEGMENT    AT 0040H
  25.         ORG    004AH
  26. CRT_COLS    DB    ?        ;CURRENT NUMBER OF COLUMNS
  27.         ORG    0050H
  28. CURSOR_POSN    DW    8 DUP(?)    ;CURRENT CURSOR LOCATION
  29.         ORG    0062H
  30. ACTIVE_PAGE    DB    ?        ;ACTIVE PAGE FOR CGA AND EGA
  31.         ORG    0084H
  32. BIOS_ROWS    DB    ?        ;LAST ROW NUMBER FOR EGA
  33. BIOS_SEG    ENDS
  34.  
  35. CSEG        SEGMENT
  36.         ASSUME    CS:CSEG,DS:NOTHING
  37.         ORG    0100H        ;BEGINNING FOR .COM PROGRAMS
  38. START:        JMP    INITIALIZE    ;INITIALIZATION CODE IS AT END
  39.  
  40. ;--------------------------------;
  41. ; DATA AREA USED BY THIS PROGRAM ;
  42. ;--------------------------------;
  43. HOTKEY        EQU    11H        ;SCAN CODE FOR "W" KEY
  44. SHIFT_MASK    EQU    00001000B    ;MASK FOR ALT KEY
  45. ;
  46. COPYRIGHT    DB    "SNIPPER 2.3 (c) 1987 Ziff Communications Co."
  47.         DB    13,10,"PC Magazine ",254," T Kihlken (+JT+TG)"
  48.         DB    13,10,"Hotkey is ALT-W",13,10,"$",1AH
  49. INSTALLED_MSG    DB    "Already Installed",13,10,"$"
  50. BAD_DOS_MSG    DB    "Requires DOS 2.0+",13,10,"$"
  51. OLDINT09    DD    ?    ;OLD KEYBOARD BREAK INTERRUPT VECTOR
  52. OLDINT13    DD    ?    ;OLD BIOS DISK IO INTERRUPT VECTOR
  53. OLDINT16    DD    ?    ;OLD KEYBOARD INTERRUPT VECTOR
  54. OLDINT21    DD    ?    ;OLD DOS FUNCTION INTERRUPT VECTOR
  55. ERR_STAT    DB    ?    ;ERROR STATUS DURING FILE OUTPUT
  56. FILE_PROMPT    DB    "Enter Filename: "
  57. FILENAME    DB    "SCREEN.CUT"    ;THE DEFAULT FILENAME
  58.         DB    15 DUP (0)    ;LEAVE ROOM FOR DRIVE AND PATH
  59. BUFF_NEXT    DW      BUFF_START    ;POINTER TO NEXT KEY IN BUFFER
  60. BUFF_LAST    DW      BUFF_START    ;POINTER TO LAST KEY IN BUFFER
  61. BUFF_START    EQU    OFFSET INITIALIZE
  62. BUFF_SIZE    EQU    25*(80+2)    ;ROOM FOR 25 ROWS OF 80 COLUMNS
  63. BUFF_END    DW    BUFF_START+BUFF_SIZE
  64. TOP_LEFT    LABEL    WORD        ;FIRST CORNER OF WINDOW
  65. LEFT_SIDE    DB    0        ;COLUMN NUMBER OF LEFT SIDE
  66. TOP_ROW        DB    0        ;ROW NUMBER OF TOP SIDE
  67. BOT_RIGHT    LABEL    WORD        ;SECOND CORNER OF WINDOW
  68. RIGHT_SIDE    DB    ?        ;COLUMN NUMBER OR RIGHT SIDE
  69. BOT_ROW        DB    ?        ;ROW NUMBER OF BOTTOM
  70. SEND_CHAR    DW    ?        ;POINTER TO CHARACTER HANDLER
  71. SEND_KEYS    DB    0        ;IF=1, USE KEYSTROKES FROM BUFFER
  72. WRIT_FILE    DB    0        ;IF=1, NEED TO WRITE TO DISK
  73. BUSY_FLAGS    DB    0        ;BIT MASKED AS FOLLOWS:
  74.                     ; 1 - DOS IS ACTIVE
  75.                     ; 2 - BIOS IO IS ACTIVE
  76.                     ; 4 - SNIPPER IS ACTIVE
  77. DOS_STAT    DB    0        ;CURRENT DOS FUNCTION
  78. END_FLAG    DB    0        ;"END"  Key Pressed =1          V2.3
  79. PGDN_FLAG    DB    0        ;"PGDN" Key Pressed =1          V2.3
  80. HOME_FLAG    DB    0        ;"HOME" Key Pressed =1          V2.3
  81. PGUP_FLAG    DB    0        ;"PGUP" Key Pressed =1          V2.3
  82. SCRN_ROWS    DB    ?
  83.  
  84. HELP_MENU    DB    201,10 DUP(205),187
  85.         DB    186," F - File ",186
  86.         DB    186," P - Print",186
  87.         DB    186," S - Save ",186
  88.         DB    186," G - Get  ",186
  89.         DB    186,"Esc- Quit ",186
  90.         DB    200,10 DUP(205),188
  91.  
  92. ;------------------------------------------------------------------;
  93. ; SNIPPER BUILDS THE WINDOW AND ACCEPTS COMMANDS FROM THE KEYBOARD ;
  94. ;------------------------------------------------------------------;
  95. SNIPPER        PROC    NEAR
  96.         ASSUME    DS:CSEG, ES:BIOS_SEG
  97.  
  98.         MOV    SCRN_ROWS,24    ;DEFAULT NUMBER OF ROWS
  99.  
  100.         MOV    AH,12H
  101.         MOV    BL,10H        ;GET EGA INFO
  102.         INT    10H
  103.         CMP    BL,10H        ;DID BL CHANGE?
  104.         JE    NOT_EGA        ;IF NO, EGA IS NOT PRESENT
  105.         TEST    BYTE PTR ES:[00087H],8 ;IS EGA ACTIVE?
  106.         JNZ    NOT_EGA
  107.         MOV    AL,BIOS_ROWS
  108.         MOV    SCRN_ROWS,AL
  109. NOT_EGA:
  110.         XOR    BX,BX        ;BX IS INCREMENT FOR ROW/COLUMN
  111. GET_KB_KEY1:
  112.         MOV    DX,TOP_LEFT    ;GET LOCATION OF FIRST CORNER
  113.         ADD    DH,BH        ;ADD IN THE ROW INCREMENT
  114.         ADD    DL,BL        ;ADD IN THE COLUMN INCREMENT
  115.         CMP    DL,0        ;AT LEFT EDGE OF SCREEN?
  116.         JGE    NOT_LEFT_EDGE
  117. FORCE_RIGHT:    MOV    DL,CRT_COLS    ;JUMP TO THE RIGHT EDGE          V2.3
  118.         DEC    DL
  119. NOT_LEFT_EDGE:
  120.         CMP    DL,CRT_COLS    ;AT RIGHT EDGE OF SCREEN YET?
  121.         JB    NOT_RIGHT_EDGE    ;IF NOT, KEEP MOVING RIGHT
  122. FORCE_LEFT:    XOR    DL,DL        ;IF YES, WRAP TO LEFT EDGE      V2.3
  123. NOT_RIGHT_EDGE:
  124.         CMP    DH,0        ;AT TOP OF SCREEN YET?
  125.         JGE    NOT_AT_TOP
  126. FORCE_BOTTOM:    MOV    DH,SCRN_ROWS    ;JUMP DOWN TO THE BOTTOM      V2.3
  127. NOT_AT_TOP:
  128.         CMP    DH,SCRN_ROWS    ;AT BOTTOM OF SCREEN?
  129.         JLE    NOT_AT_BOTTOM
  130. FORCE_TOP:    XOR    DH,DH        ;JUMP BACK TO THE TOP          V2.3
  131. NOT_AT_BOTTOM:
  132.         MOV    TOP_LEFT,DX    ;SAVE NEW CORNER LOCATION
  133.         CALL    REV_VIDEO    ;CHANGE IT TO REVERSE VIDEO
  134.         XOR    AH,AH        ;BIOS KEYBOARD INPUT
  135.         INT    16H        ;GET A KEYSTROKE
  136.         PUSH    AX
  137.         CALL    REV_VIDEO    ;PUT ATTRIBUTE BACK TO NORMAL
  138.         POP    AX
  139.         CMP    AH,1        ;IS IT ESCAPE?
  140.         JNE    NOT_ESC
  141.         RET            ;JUST RETURN TO EXIT
  142. NOT_ESC:
  143.         MOV    BX,0FF00H    ;INCREMENT TO SUBTRACT ONE ROW
  144.         CMP    AH,48H        ;IS IT UP ARROW?
  145.         JE    GET_KB_KEY1
  146.         MOV    BX,0100H    ;INCREMENT TO ADD ONE ROW
  147.         CMP    AH,50H        ;IS IT DOWN ARROW?
  148.         JE    GET_KB_KEY1
  149.         MOV    BX,0001H    ;INCREMENT TO ADD ONE COLUMN
  150.         CMP    AH,4DH        ;IS IT RIGHT ARROW?
  151.         JE    GET_KB_KEY1
  152.         MOV    BX,00FFH    ;INCREMENT TO SUBTRACT ONE COLUMN
  153.         CMP    AH,4BH        ;IS IT LEFT ARROW?
  154.         JE    GET_KB_KEY1
  155.         CMP     AH,47H        ;IS IT HOME KEY?          V2.3
  156.         JE    FORCE_LEFT    ;JUMP TO LEFT SCREEN EDGE      V2.3
  157.         CMP    AH,49H        ;IS IT PGUP KEY?          V2.3
  158.         JE    FORCE_TOP    ;JUMP TO TOP SCRREN EDGE      V2.3
  159.         CMP     AH,4FH        ;IS IT END KEY?              V2.3
  160.         JE    FORCE_RIGHT    ;JUMP TO RIGHT SCREEN EDGE      V2.3
  161.         CMP    AH,51H        ;IS IT PGDN KEY?          V2.3
  162.         JE    FORCE_BOTTOM    ;JUMP TO BOTTOM SCREEN EDGE      V2.3
  163.         XOR    BX,BX
  164.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  165.         JNE    NOT_CR
  166.         MOV    DX,TOP_LEFT    ;A CARRIAGE RETURN WAS PRESSED
  167.         MOV    BOT_RIGHT,DX    ;INITIALIZE THE SECOND CORNER
  168.         CALL    REV_VIDEO    ;CHANGE IT BACK TO REVERSE VIDEO
  169.         JMP    SHORT GET_KB_KEY2
  170. NOT_CR:
  171.         CMP    AH,22H        ;IS IT THE "G" KEY
  172.         JE    TYPE_BUFF    ;IF YES, THAN GET THE WINDOW
  173.         JMP    GET_KB_KEY1    ;JUST GET ANOTHER KEY
  174. TYPE_BUFF:
  175.         MOV    SEND_KEYS,1    ;SIGNAL TO SEND THE KEYS
  176.         RET
  177. GET_KB_KEY2:
  178.         MOV    END_FLAG,0    ; CLEAR END FLAG          V2.3
  179.         MOV    PGDN_FLAG,0    ; CLEAR PGDN FLAG          V2.3
  180.         MOV    HOME_FLAG,0    ; CLEAR HOME FLAG          V2.3
  181.         MOV    PGUP_FLAG,0    ; CLEAR PGUP FLAG          V2.3
  182.         XOR    AH,AH
  183.         INT    16H        ;GET A KEYSTROKE
  184. GOT_KEY2:    MOV    DX,BOT_RIGHT
  185.         CMP    AH,4BH        ;IS IT LEFT ARROW?
  186.         JE    SUB_COL        ;SUBTRACT A COLUMN FROM WINDOW
  187.         CMP    AH,4DH        ;IS IT RIGHT ARROW?
  188.         JE    ADD_COL        ;ADD A COLUMN TO THE WINDOW
  189.         CMP    AH,48H        ;IS IT UP ARROW?
  190.         JE    SUB_ROW        ;SUBTRACT A ROW FROM WINDOW
  191.         CMP    AH,4FH        ;IS IT "END"?              V2.3
  192.         JE    GOT_END        ;GO TO RIGHT EDGE OF SCREEN      V2.3
  193.         CMP    AH,51H        ;IS IT "PGDN"?              V2.3
  194.         JE    GOT_PGDN    ;GO TO BOTTOM EDGE OF SCREEN      V2.3
  195.         CMP    AH,50H        ;IS IT DOWN ARROW?
  196.         JE    ADD_ROW        ;ADD A ROW TO THE WINDOW
  197.         CMP    AH,47H        ;IS IT "HOME"?              V2.3
  198.         JE    GOT_HOME    ;GO TO LEFT EDGE OF WINDOW      V2.3
  199.         CMP    AH,49H        ;IS IT "PGUP"?              V2.3
  200.         JE    GOT_PGUP    ;GO TO TOP EDGE OF WINDOW      V2.3
  201.         JMP    NOT_ARROW_KEY
  202. GOT_HOME:    MOV    HOME_FLAG,1    ;"HOME" KEY PRESSED          V2.3
  203. SUB_COL:
  204.         MOV    DX,BOT_RIGHT    ;2ND CORNER COORDS          V2.3
  205.         DEC    DL        ;SUBTRACT A COLUMN
  206.         CMP    DL,LEFT_SIDE    ;DONT ERASE IT COMPLETELY
  207.         JL    GET_KB_KEY2
  208.         MOV    RIGHT_SIDE,DL    ;SAVE NEW RIGHT SIDE COLUMN
  209.         INC    DL
  210.         JMP    SHORT COL_LOOP
  211. GOT_END:    MOV    END_FLAG,1    ;"END" KEY PRESSED          V2.3
  212. ADD_COL:
  213.         MOV    DX,BOT_RIGHT    ;2ND CORNER COORDS          V2.3
  214.         INC    DL        ;ADD A COLUMN
  215.         CMP    DL,CRT_COLS    ;AT RIGHT EDGE OF SCREEN?
  216.         JAE    GET_KB_KEY2    ;STOP WHEN SCREEN IS FILLED
  217.         MOV    RIGHT_SIDE,DL    ;SAVE NEW RIGHT SIDE COLUMN
  218. COL_LOOP:
  219.         CALL    REV_VIDEO    ;REVERSE THIS CHARACTER
  220.         DEC    DH        ;MOVE TO NEXT ROW
  221.         CMP    DH,TOP_ROW    ;AT TOP ROW YET?
  222.         JGE    COL_LOOP    ;LOOP UNTIL AT TOP ROW
  223.         CMP    END_FLAG,1    ;IF "END", REPEAT TO RIGHT EDGE      V2.3
  224.         JE    ADD_COL        ;ADD ANOTHER COLUMN          V2.3
  225.         CMP    HOME_FLAG,1    ;IF "HOME", REPEAT TO LEFT EDGE      V2.3
  226.         JE    SUB_COL        ;REMOVE ANOTHER COLUMN          V2.3
  227. GET_KB_K2_JMP:    JMP    GET_KB_KEY2    ;                  V2.3
  228.  
  229. GOT_PGUP:    MOV    PGUP_FLAG,1    ;"PGUP" KEY PRESSED          V2.3
  230. SUB_ROW:
  231.         MOV    DX,BOT_RIGHT    ;2ND CORNER COORDS          V2.3
  232.         DEC    DH
  233.         CMP    DH,TOP_ROW    ;AT TOP OF WINDOW?
  234.         JL    GET_KB_K2_JMP    ;DONT ERASE IT COMPLETELY
  235.         MOV    BOT_ROW,DH
  236.         INC    DH
  237.         JMP    SHORT ROW_LOOP
  238. GOT_PGDN:    MOV    PGDN_FLAG,1    ;"PGDN" KEY PRESSED          V2.3
  239. ADD_ROW:
  240.         MOV    DX,BOT_RIGHT    ;2ND CORNER COORDS          V2.3
  241.         INC    DH
  242.         CMP    DH,SCRN_ROWS    ;AT BOTTOM OF SCREEN?
  243.         JG    GET_KB_K2_JMP    ;STOP WHEN SCREEN IS FILLED
  244.         MOV    BOT_ROW,DH
  245. ROW_LOOP:
  246.         CALL    REV_VIDEO    ;REVERSE THIS CHARACTER
  247.         DEC    DL        ;MOVE TO NEXT COLUMN
  248.         CMP    DL,LEFT_SIDE    ;AT LEFT EDGE YET?
  249.         JGE    ROW_LOOP    ;CONTINUE UNTIL AT LEFT EDGE
  250.         CMP    PGDN_FLAG,1    ;IF "PGDN", REPEAT TO BOTTOM EDGE V2.3
  251.         JE    ADD_ROW        ;ADD ANOTHER ROW          V2.3
  252.         CMP    PGUP_FLAG,1    ;IF "PGUP", REPEAT TO TOP EDGE      V2.3
  253.         JE    SUB_ROW        ;REMOVE ANOTHER ROW          V2.3
  254.         JMP    GET_KB_KEY2
  255. NOT_ARROW_KEY: 
  256.         CMP    AH,19H        ;WAS IT THE "P" KEY?
  257.         JNE    NOT_P
  258.         MOV    SEND_CHAR,OFFSET PRINT_CHAR
  259.         JMP    READ_WINDOW
  260. NOT_P:
  261.         MOV    BUFF_NEXT,BUFF_START
  262.         MOV    BUFF_LAST,BUFF_START
  263.         MOV    SEND_CHAR,OFFSET BUFF_CHAR
  264.  
  265.         CMP    AH,1FH        ;WAS IT THE "S" KEY?
  266.         JNE    NOT_S
  267.         MOV    SEND_CHAR,OFFSET BUFF_CHAR
  268.         JMP    READ_WINDOW
  269. NOT_S:
  270.         CMP    AH,22H        ;IS IT THE "G" KEY
  271.         JNE    NOT_G
  272.         MOV    SEND_KEYS,1
  273.         JMP    READ_WINDOW
  274. NOT_G:
  275.         CMP    AH,21H        ;IS IT THE "F" KEY
  276.         JNE    NOT_F
  277.         MOV    WRIT_FILE,0
  278.         CALL    GET_FILENAME
  279.         CMP    WRIT_FILE,-1    ;WAS ESCAPE REQUESTED?
  280.         JE    ERASE_BOX
  281.         CALL    READ_WINDOW
  282.         MOV    WRIT_FILE,1
  283.         TEST    BUSY_FLAGS,00000011B     ;IS INT21 OR INT13 BUSY?
  284.         JNZ    RETURN        ;IF YES, WAIT TILL LATER
  285.         CALL    WRITE_TO_FILE    ;IF NOT, DO IT NOW
  286. RETURN:
  287.         RET
  288. NOT_F:
  289.         CMP    AH,1        ;IS IT ESCAPE?
  290.         JE    ERASE_BOX ;IF YES, ERASE BOX AND EXIT
  291.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  292.         JE    DISPLAY_HELP    ;IF YES, DISPLAY HELP
  293.         JMP    GET_KB_KEY2    ;OTHERWISE JUST GET ANOTHER KEY
  294. ERASE_BOX:
  295.         MOV    SEND_CHAR,OFFSET RETURN
  296.         JMP    READ_WINDOW
  297. DISPLAY_HELP:
  298.         CALL    EXCHANGE_HELP    ;PUT UP THE HELP MENU
  299.         XOR    AH,AH
  300.         INT    16H        ;GET ANOTHER KEYSTROKE
  301.         PUSH    AX        ;SAVE THE KEYSTROKE
  302.         CALL    EXCHANGE_HELP    ;PULL DOWN THE HELP MENU
  303.         POP    AX        ;GET BACK THE KEYSTROKE
  304.         JMP    GOT_KEY2
  305. ;*********************************************************************
  306. REV_VIDEO:
  307.         CALL    READ_CHAR    ;READ CHARACTER AND ATTRIBUTE
  308.         MOV    BL,AH        ;SAVE ATTRIBUTE IN BL
  309.         AND    BL,10001000B    ;GET BLINK AND INTENSITY BITS
  310.         AND    AH,01110111B    ;NOW LOOK ONLY AT COLOR BITS
  311.         MOV    CL,4        ;ROTATE FOUR COUNTS
  312.         ROR    AH,CL        ;ROTATE FOREGROUND AND BACKGROUND
  313.         OR    BL,AH        ;PUT BACK BLINK AND INTENSITY BITS
  314.         CALL    DISPLAY_CHAR    ;WRITE CHARACTER AND ATTRIBUTE
  315.         RET
  316. ;*********************************************************************
  317. READ_WINDOW:
  318.         MOV    DX,TOP_LEFT    ;GET LOCATION OF FIRST CORNER
  319. READ_LOOP:
  320.         CALL    REV_VIDEO    ;PUT ATTRIBUTE BACK TO NORMAL
  321.         CALL    READ_CHAR    ;READ THE CHARACTER
  322.         CALL    SEND_CHAR    ;CALL TO THE POINTER
  323.         INC    DL        ;NEXT CHAR IN ROW
  324.         CMP    DL,RIGHT_SIDE    ;AT THE RIGHT BORDER YET?
  325.         JLE    READ_LOOP    ;DO ALL CHARACTERS IN THIS ROW
  326.         CALL    CR_LF        ;SEND CR-LF AFTER EACH ROW
  327.         INC    DH        ;MOVE TO NEXT ROW
  328.         MOV    DL,LEFT_SIDE    ;BACK TO LEFT EDGE
  329.         CMP    DH,BOT_ROW    ;AT THE BOTTOM BORDER YET?
  330.         JLE    READ_LOOP    ;READ ENTIRE WINDOW
  331.         RET
  332. ;*********************************************************************
  333. CR_LF:
  334.         MOV    AL,13
  335.         CALL    SEND_CHAR    ;SEND A CARRIAGE RETURN
  336.         MOV    AL,10
  337.         CALL    SEND_CHAR    ;SEND A LINE FEED
  338.         RET
  339. ;*********************************************************************
  340. DISPLAY_CHAR:
  341.         PUSH    BX        ;SAVE THE ATTRIBUTE
  342.         CALL    GET_CURS_ADDR    ;GET ADDRESS OF BIOS CURSOR
  343.         MOV    ES:[BX],DX    ;TELL BIOS WHERE THE CURSOR IS
  344.         POP    BX        ;GET BACK THE ATTRIBUTE
  345.         MOV    BH,ACTIVE_PAGE    ;GET ACTIVE PAGE
  346.         PUSH    CX        ;SAVE THE LOOP COUNT
  347.         MOV    CX,1        ;WRITE 1 CHARACTER
  348.         MOV    AH,9        ;WRITE CHARACTER AND ATTRIBUTE
  349.         INT    10H
  350.         POP    CX        ;RECOVER LOOP COUNT
  351.         RET            ;DONE WRITING THE CHARACTER
  352. ;*********************************************************************
  353. READ_CHAR:
  354.         CALL    GET_CURS_ADDR    ;GET ADDRESS OF BIOS CURSOR
  355.         MOV    ES:[BX],DX    ;TELL BIOS WHERE THE CURSOR IS
  356.         MOV    BH,ACTIVE_PAGE    ;GET ACTIVE PAGE
  357.         MOV    AH,8        ;BIOS FUNCTION TO READ CHARACTER
  358.         INT    10H        ;READ THE CHARACTER/ATTRIBUTE
  359.         RET
  360. ;*********************************************************************
  361. PRINT_CHAR:
  362.         PUSH    DX
  363.         XOR    AH,AH        ;USE FUNCTION 0
  364.         XOR    DX,DX        ;PRINTER NUMBER 0
  365.         INT    17H        ;BIOS PRINT CHARACTER FUNCTION
  366.         ROR    AH,1        ;LOOK AT BIT ZERO
  367.         JNC    PRINT_OK    ;DID A TIMEOUT OCCUR?
  368.         MOV    SEND_CHAR,OFFSET RETURN
  369. PRINT_OK:
  370.         POP    DX
  371.         RET            ;DONE PRINTING CHARACTER
  372. ;*********************************************************************
  373. BUFF_CHAR:
  374.         MOV    BX,BUFF_LAST    ;GET LOCATION OF LAST CHARACTER
  375.         MOV    [BX],AL        ;PUT THE CHARACTER IN BUFFER
  376.         INC    BX        ;ADVANCE THE POINTER
  377.         MOV    BUFF_LAST,BX    ;CHECK FOR BUFFER FULL
  378.         CMP    BX,BUFF_END    ;IS THE BUFFER FULL YET?
  379.         JNE    BUFF_OK        ;IF NOT, KEEP GOING
  380.         MOV    SEND_CHAR,OFFSET RETURN
  381. BUFF_OK:
  382.         RET            ;NOW ITS IN THE BUFFER
  383. ;*********************************************************************
  384. GET_CURS_ADDR:
  385.         MOV    BL,ACTIVE_PAGE    ;GET THE CURRENT PAGE NUMBER
  386.         XOR    BH,BH        ;CONVERT TO A WORD OFFSET
  387.         SHL    BX,1        ;TIMES TWO FOR A WORD
  388.         ADD    BX,OFFSET CURSOR_POSN ;ADD IN BASE ADDRESS
  389.         RET
  390. ;*********************************************************************
  391. EXCHANGE_HELP:
  392.         XOR    DX,DX        ;START AT TOP LEFT CORNER
  393.         LEA    SI,HELP_MENU
  394. EXCHANGE_LOOP:
  395.         CMP    DL,12        ;AT LAST COLUMN IN THIS ROW YET?
  396.         JL    SWAP_CHAR
  397.         XOR    DL,DL        ;BACK TO FIRST COLUMN
  398.         INC    DH        ;DO THE NEXT ROW
  399.         CMP    DH,7        ;AT LAST ROW YET?
  400.         JL    SWAP_CHAR    ;QUIT WHEN LAST ROW IS DONE
  401.         RET
  402. SWAP_CHAR:
  403.         CALL    READ_CHAR    ;READ CHARACTER AT THIS POSITION
  404.         XCHG    AL,CS:[SI]    ;SWAP WITH THE HELP TEXT
  405.         MOV    BL,AH        ;ATTRIBUTE IS THE SAME
  406.         CALL    DISPLAY_CHAR    ;PUT NEW CHARACTER ON SCREEN
  407.         INC    DL        ;POINT TO NEXT POSITION
  408.         INC    SI
  409.         JMP EXCHANGE_LOOP
  410. ;*********************************************************************
  411. GET_FILENAME:
  412.         LEA    SI,FILE_PROMPT    ;POINT TO THE PROMPT FOR SOURCE
  413.         XOR    DI,DI        ;USE THE PSP FOR BUFFER
  414.         XOR    DX,DX        ;PUT PROMPT AT TOP LEFT CORNER
  415.         MOV    CX,40        ;USE MAX OF 40 CHARACTERS
  416. DISPLAY_PROMPT:
  417.         PUSH    CX        ;SAVE LOOP COUNT
  418.         CALL    READ_CHAR    ;GET CHARACTER ON THIS LINE
  419.         MOV    CS:[DI],AX    ;STORE IT IN THE PSP
  420.         INC    DI        ;ADD TWO FOR NEXT CHARACTER
  421.         INC    DI
  422.         MOV    AL,CS:[SI]    ;GET NEXT PROMPT CHARACTER
  423.         INC    SI        ;NEXT CHARACTER IN PROMPT
  424.         MOV    BL,47H        ;ATTRIBUTE FOR PROMPT
  425.         CALL    DISPLAY_CHAR    ;PUT UP THE PROMPT CHARACTER
  426.         INC    DL        ;POINT TO NEXT COLUMN
  427.         POP    CX        ;GET BACK LOOP COUNT
  428.         LOOP    DISPLAY_PROMPT    ;ENTIRE PROMPT AND FILENAME
  429. FIND_LAST_LETTER:
  430.         DEC    SI        ;BACKUP TO LAST LETTER
  431.         DEC    DL        ;BACKUP TO LAST COLUMN
  432.         CMP    BYTE PTR [SI],0    ;IS THIS A LETTER?
  433.         JE    FIND_LAST_LETTER;BACKUP UNTILL A LETTER IS FOUND
  434.         INC    DL        ;PUT BLINKING BOX AT LAST LETTER
  435. READ_KB:
  436.         MOV    AL,219        ;ASCII FOR BOX CHARACTER
  437.         MOV    BL,47H+80H    ;MAKE IT A BLINKING BOX CHARACTER
  438.         CALL    DISPLAY_CHAR    ;WRITE THE BLINKING BOX
  439. ;
  440.         XOR    AH,AH        ;FUNCTIO 0 TO GET NEXT KEY
  441.         INT    16H        ;BIOS KEYBOARD INPUT
  442.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  443.         JE    ERASE_PROMPT
  444.         CMP    AL,8        ;IS IT A BACKSPACE?
  445.         JE    BACK_SPACE
  446.         CMP    AH,1        ;IS IT ESCAPE?
  447.         JE    ESC_RET
  448.         CMP    AL,"."        ;IS IT A VALID LETTER?
  449.         JL    READ_KB
  450.         CMP    AL,"z"        ;IS IT A VALID LETTER?
  451.         JG    READ_KB
  452.         CMP    DL,39        ;ONLY ALLOW 40 CHARACTERS
  453.         JGE    READ_KB
  454. TTY_KEY:
  455.         MOV    BL,47H        ;ATTRIBUTE FOR FILENAME
  456.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  457.         INC    DL        ;MOVE TO NEXT COLUMN
  458.         JMP    READ_KB        ;GET ANOTHER KEYSTROKE
  459. BACK_SPACE:
  460.         CMP    DL,16        ;AT BEGINNING OF LINE?
  461.         JLE    READ_KB        ;IF YES, CAN'T BACKUP FROM HERE
  462.         MOV    AL,0        ;WRITE A NORMAL BLANK (ASCII 0)
  463.         MOV    BL,47H        ;ATTRIBUTE FOR FILENAME
  464.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  465.         DEC    DL        ;BACKUP THE CURSOR
  466.         JMP    READ_KB        ;THEN GET THE NEXT KEY
  467. ESC_RET:
  468.         MOV    WRIT_FILE,-1    ;INDICATE ESCAPE IS REQUESTED
  469. ERASE_PROMPT:
  470.         XOR    AL,AL        ;GET RID OF THE CURSOR
  471.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  472.         LEA    DI,FILE_PROMPT    ;COPY TO FILENAME
  473.         XOR    SI,SI        ;COPY FROM PSP
  474.         XOR    DX,DX        ;PROMPT IS AT ROW ZERO
  475.         MOV    CX,40        ;COPY ALL 40 CHARACTERS
  476. ERASE_LOOP:
  477.         CALL    READ_CHAR    ;GET CHARACTER ON THIS LINE
  478.         MOV    CS:[DI],AL    ;PUT IN BACK IN MEMORY
  479.         INC    DI
  480.         MOV    AX,CS:[SI]    ;GET THE ORIGINAL CHARACTER BACK
  481.         MOV    BL,AH        ;PUT ATTRIBUTE INTO BL
  482.         INC    SI
  483.         INC    SI
  484.         CALL    DISPLAY_CHAR    ;WRITE ORIGINAL CHARACTER
  485.         INC    DL        ;MOVE TO NEXT COLUMN
  486.         LOOP    ERASE_LOOP    ;ERASE THE ENTIRE PROMPT
  487.         RET
  488. SNIPPER        ENDP
  489.  
  490. ;---------------------------------------------------------------------;
  491. ; THIS COPIES THE BUFFER CONTENTS TO A FILE. IT SHOULD ONLY BE CALLED ;
  492. ; WHEN DOS IS IN A STABLE AND REENTRANT CONDITION.                    ;
  493. ;---------------------------------------------------------------------;
  494. WRITE_TO_FILE    PROC    NEAR
  495.         ASSUME    DS:NOTHING, ES:NOTHING
  496.  
  497.         MOV    WRIT_FILE,0    ;TURN OFF REQUEST FLAG
  498.         PUSH    AX        ;MUST PRESERVE ALL REGISTERS
  499.         PUSH    BX
  500.         PUSH    CX
  501.         PUSH    DX
  502.         PUSH    DS
  503.         PUSH    ES
  504.         PUSH    CS
  505.         POP    DS
  506.         ASSUME    DS:CSEG        ;DS POINTS TO OUR CODE SEGMENT
  507.              MOV    AX,3524H    ;GET DOS CRITICAL ERROR VECTOR
  508.         INT    21H        ;DOS FUNCTION TO GET VECTOR
  509.         PUSH    BX        ;SAVE OLD VECTOR ON STACK
  510.         PUSH    ES
  511.  
  512. ; REPLACE THE DOS SEVERE ERROR INTERRUPT WITH OUR OWN ROUTINE.
  513.  
  514.         MOV    DX,OFFSET NEWINT24
  515.         MOV    AX,2524H    ;SETUP TO CHANGE INT 24h VECTOR
  516.         INT    21H        ;CHANGE DOS SEVERE ERROR VECTOR
  517.         MOV    DX,OFFSET FILENAME ;POINT TO FILENAME
  518.  
  519. ; FIRST TRY TO OPEN THE FILE.  IF DOS RETURNS WITH THE CARRY FLAG SET,
  520. ; THE FILE DIDN'T EXIST AND WE MUST CREATE IT.  ONCE THE FILE IS OPENED,
  521. ; ADVANCE THE FILE POINTER TO THE END OF FILE TO APPEND.
  522.  
  523.         MOV    AX,3D02H    ;DOS FUNCTION TO OPEN FILE
  524.         INT    21H        ;DOS WILL RETURN WITH CARRY FLAG
  525.         JC    FILE_NOT_FOUND    ;SET IF FILE DOESN'T EXIST.
  526.         MOV    BX,AX        ;KEEP HANDLE IN BX ALSO
  527.         XOR    CX,CX        ;MOVE DOS FILE POINTER TO THE
  528.         XOR    DX,DX        ;END OF THE FILE. THIS LETS US
  529.         MOV    AX,4202H    ;APPEND THIS TO AN EXISTING FILE
  530.         INT    21H        ;DOS FUNCTION TO MOVE POINTER
  531.         JNC    WRITE_FILE    ;IF NO ERROR, CONTINUE TO WRITE
  532. DOS_ERROR:
  533.         CMP    ERR_STAT,0    ;DID A SEVERE ERROR OCCUR?
  534.         JNE    REP_VECTOR    ;IF SEVERE ERROR, JUST QUIT
  535.         JMP    SHORT CLOSE_FILE;JUST CLOSE THE FILE
  536.  
  537. FILE_NOT_FOUND:    CMP    ERR_STAT,0    ;DID A SEVERE ERROR OCCUR?
  538.         JNE    REP_VECTOR    ;IF SEVERE ERROR, JUST QUIT
  539.         MOV    CX,0020H    ;ATTRIBUTE FOR NEW FILE
  540.         MOV    AH,3CH        ;CREATE FILE FOR WRITING
  541.         INT    21H        ;DOS FUNCTION TO CREATE FILE
  542.         JC    DOS_ERROR       ;ON ANY ERROR, TAKE JUMP
  543.         MOV    BX,AX        ;SAVE HANDLE IN BX
  544. WRITE_FILE:     MOV    DX,BUFF_START    ;POINT TO BUFFER
  545.         MOV    CX,BUFF_LAST    ;GET BUFFER POINTER
  546.         SUB    CX,DX        ;NUMBER OF CHARS IN BUFFER
  547.         MOV    AH,40H        ;DOS WRITE TO A DEVICE FUNCTION
  548.         INT    21H        ;WRITE TO THE FILE
  549. CLOSE_FILE:
  550.         MOV    AH,3EH        ;DOS FUNCTION TO CLOSE THE FILE
  551.         INT    21H
  552. REP_VECTOR:
  553.         POP    DS        ;GET INT 24H VECTOR FROM STACK
  554.         POP    DX
  555.         MOV    AX,2524H    ;RESTORE CRITICAL ERROR VECTOR
  556.         INT    21H        ;DOS FUNCTION TO CHANGE VECTOR
  557.         POP    ES        ;FINALLY RESTORE ALL REGISTERS
  558.         POP    DS
  559.         POP    DX
  560.         POP    CX
  561.         POP    BX
  562.         POP    AX
  563.         RET            ;FINISHED WRITING TO DISK
  564. WRITE_TO_FILE    ENDP
  565. ;---------------------------------------------------------------------;
  566. ; INTERRUPT 09 ROUTINE.  WATCH FOR TRIGGER KEY TO POP UP.
  567. ;---------------------------------------------------------------------;
  568. NEWINT09    PROC    FAR
  569.         ASSUME    DS:NOTHING, ES:NOTHING
  570.         STI            ;ALLOW OTHER INTERRUPTS
  571.         PUSH    AX        ;MUST SAVE PROCESSOR STATE
  572.         IN    AL,60H        ;GET THE SCAN CODE
  573.         CMP    AL,HOTKEY    ;IS IT THE HOT KEY?
  574.         JE    TRIGGER        ;IF YES, CHECK THE MASK
  575. INT09_EXIT:    POP    AX        ;RESTORE THE PROCESSOR STATE
  576.         JMP    OLDINT09    ;CONTINUE WITH ROM ROUTINE
  577.  
  578. TRIGGER:    MOV    AH,2        ;GET KEYBOARD STATUS
  579.         INT    16H        ;BIOS KEYBOARD SERVICE
  580.  
  581.         AND    AL,0FH        ;Take lo er four bits
  582.         CMP    AL,SHIFT_MASK    ;IS ALT KEY DOWN?
  583.         JNZ    INT09_EXIT    ;IF NOT, IGNORE IT
  584.         TEST    BUSY_FLAGS,00000100B ;IS SNIPPER ALREADY ACTIVE?
  585.         JNZ    INT09_EXIT    ;IF ACTIVE, THEN EXIT
  586.         OR    BUSY_FLAGS,00000100B ;ITS ACTIVE NOW
  587.         PUSHF
  588.         CALL    OLDINT09    ;LET ROM PROCESS THE KEY
  589.         PUSH    BX        ;MUST PRESERVE ALL REGISTERS
  590.         PUSH    CX
  591.         PUSH    DX
  592.         PUSH    BP
  593.         PUSH    SI
  594.         PUSH    DI
  595.         PUSH    DS
  596.         PUSH    ES
  597.         PUSH    CS
  598.         POP    DS        ;SET DS TO CSEG
  599.  
  600.         MOV    AX,BIOS_SEG    ;ES POINTS TO BIOS DATA AREA
  601.         MOV    ES,AX
  602.         ASSUME    DS:CSEG, ES:BIOS_SEG
  603.  
  604.         CALL    GET_CURS_ADDR    ;CURSOR ADDRESS FOR THIS PAGE
  605.         PUSH    ES:[BX]        ;SAVE CURSOR POSITION
  606.         CALL    SNIPPER        ;DO THE WINDOW
  607.         CALL    GET_CURS_ADDR    ;CURS0R ADDRESS FOR THIS PAGE
  608.         POP    ES:[BX]        ;GET BACK CURSOR  POSITION
  609.         AND    BUSY_FLAGS,11111011B  ;SNIPPER IS NOT ACTIVE
  610.  
  611.         POP    ES        ;RESTORE ALL REGISTERS
  612.         POP    DS
  613.         POP    DI
  614.         POP    SI
  615.         POP    BP
  616.         POP    DX
  617.         POP    CX
  618.         POP    BX
  619.         POP    AX
  620.         IRET            ;NOW WERE ALL DONE
  621. NEWINT09    ENDP
  622. ;---------------------------------------------------------------------;
  623. ; INTERRUPT 13 ROUTINE. SET BIOS BUST BIT                             ;
  624. ;---------------------------------------------------------------------;
  625. NEWINT13    PROC    FAR
  626.         ASSUME    DS:NOTHING, ES:NOTHING
  627.  
  628.         OR    BUSY_FLAGS,00000010B    ;SET BIOS BUSY BIT
  629.         PUSHF
  630.         CALL    OLDINT13    ;DO THE BIOS FUNCTION
  631.         PUSHF            ;SAVE RESULT FLAGS
  632.         AND    BUSY_FLAGS,11111101B    ;CLEAR BIOS BUSY BIT
  633.         POPF            ;GET BACK RESULT FLAGS
  634.         STI            ;MUST RETURN WITH INTERUPTS ON
  635.         RET    2        ;RETURN BIOS RESULT FLAGS
  636.  
  637. NEWINT13    ENDP
  638. ;---------------------------------------------------------------------;
  639. ; INTERRUPT 16 ROUTINE. INSERT KEYSTROKES FROM BUFFER                 ;
  640. ;---------------------------------------------------------------------;
  641. NEWINT16    PROC    FAR
  642.         ASSUME    DS:NOTHING, ES:NOTHING
  643.         PUSH    BX
  644.         CMP    SEND_KEYS,1    ;SENDING KEYS FROM BUFFER?
  645.         JE    INSERT_KEY    ;IF YES, THEN GET NEXT ONE
  646.         CMP    WRIT_FILE,1    ;ANYTHING TO WRITE TO DISK?
  647.         JE    CHECK_DOS_STAT    ;IF YES, THIS IS THE TIME
  648. BIOS_KB:
  649.         POP    BX
  650.         JMP    OLDINT16    ;JUST DO NORMAL KB ROUTINE
  651. CHECK_DOS_STAT:
  652.         CMP    DOS_STAT,0AH    ;DOING READ STRING?
  653.         JE    BEGIN_NOW    ;IF YES, ITS SAFE TO BEGIN
  654.         CMP    DOS_STAT,8    ;DOING KEYBOARD INPUT?
  655.         JNE    BIOS_KB        ;IF YES, ITS SAFE TO BEGIN
  656. BEGIN_NOW:
  657.         STI            ;GET INTERRUPTS BACK ON
  658.         CALL    WRITE_TO_FILE    ;EMPTY THE BUFFER
  659.         JMP    BIOS_KB        ;CONTINUE WITH BIOS ROUTINE
  660. INSERT_KEY:
  661.         STI            ;INTERRUPTS BACK ON
  662.         MOV    BX,BUFF_NEXT    ;GET ADDRESS OF NEXT BYTE
  663.         CMP    BX,BUFF_LAST    ;AT END OF BUFFER YET?
  664.         JL    GET_A_KEY    ;IF NOT, GET THE NEXT ONE
  665.         MOV    SEND_KEYS,0    ;WHEN DONE, TURN OFF SEND SWITCH
  666. GET_A_KEY:
  667.         MOV    AL,CS:[BX]    ;GET THE NEXT KEY CODE
  668.         CMP    AL,10        ;IS IT A LINE FEED?
  669.         JNE    NOT_LF        ;DONT RETURN THE LINE FEEDS
  670.         INC    BUFF_NEXT    ;SKIP TO NEXT KEY
  671.         JMP    INSERT_KEY
  672. NOT_LF:
  673.         CMP    AH,1        ;REQUEST FOR STATUS ONLY?
  674.         JE    RETURN_STATUS    ;IF YES, RETURN STATUS ONLY
  675.         CMP    AH,0        ;REQUEST TO GET THE NEXT KEY
  676.         JNE    BIOS_KB        ;IF NOT, IGNORE THIS FUNCTION
  677.         INC    BX        ;REMOVE THIS KEY FROM OUR BUFFER
  678.         MOV    BUFF_NEXT,BX    ;SAVE THE POINTER TO NEXT KEY
  679. RETURN_STATUS:
  680.         OR    BL,1        ;CLEAR ZERO FLAG TO INDICATE A
  681.         POP    BX        ;KEY IS AVAILIABLE
  682.         RET    2        ;RETURN WITH THESE FLAGS
  683. NEWINT16    ENDP
  684. ;---------------------------------------------------------------------;
  685. ; INTERRUPT 21 ROUTINE.  THIS ROUTINE IS USED TO MONITOR DOS FUNCTION ;
  686. ; CALLS. IF THE BUFFER NEEDS TO BE FLUSHED, IT WIL BE DONE HERE.      ;
  687. ;---------------------------------------------------------------------;
  688. NEWINT21    PROC    FAR
  689.         ASSUME    DS:NOTHING, ES:NOTHING
  690.  
  691.         PUSHF            ;SAVE ENTRY FLAGS
  692.  
  693.         STI            ;ALLOW INTERRUPTS
  694.         CMP    AH,4BH        ;IF EXEC
  695.         JNE    NOT_EXEC
  696.         POPF
  697.         JMP    CS:OLDINT21    ;GO DIRECT
  698. NOT_EXEC:
  699.         OR    AH,AH        ;DOING FUNCTION ZERO?
  700.         JNE    NOT_ZERO
  701.         MOV    AH,4CH        ;IF YES, CHANGE IT TO A 4CH
  702. NOT_ZERO:
  703.         OR    BUSY_FLAGS,00000001B    ;SET DOS BUSY BIT
  704.         MOV    DOS_STAT,AH
  705.         POPF            ;RESTORE ORIGINAL FLAGS
  706.         PUSHF            ;SIMULATE AN INTERRUPT
  707.         CALL    CS:OLDINT21    ;DO THE DOS FUNCTION
  708.         PUSHF            ;SAVE THE RESULT FLAGS
  709.         AND    BUSY_FLAGS,11111110B    ;CLEAR DOS BUSY BIT
  710.         CMP    WRIT_FILE,1    ;ANYTHING TO WRITE TO DISK?
  711.         JNE    NO_WRITE    ;IF NOT JUST RETURN
  712.         CALL    WRITE_TO_FILE    ;SAFE TO ACCESS DISK NOW
  713. NO_WRITE:
  714.         POPF            ;RECOVER DOS RESULT FLAGS
  715.         STI
  716.         RET    2        ;RETURN WITH DOS RESULT FLAGS
  717. NEWINT21    ENDP
  718.  
  719. ;---------------------------------------------------------------------;
  720. ; NEW INTERRUPT 24H (CRITICAL DOS ERROR).  THIS INTERRUPT IS ONLY IN  ;
  721. ; EFFECT ONLY DURING A WRITE SCREEN.  IT IS REQUIRED TO SUPPRESS THE  ;
  722. ; 'ABORT, RETRY, IGNORE' MESSAGE.  ALL FATAL DISK ERRORS ARE IGNORED. ;
  723. ;---------------------------------------------------------------------;
  724. NEWINT24    PROC    FAR
  725.         ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING
  726.         STI            ;TURN INTERRUPTS BACK ON
  727.         INC     ERR_STAT    ;SET THE ERROR FLAG
  728.          XOR    AL,AL        ;TELLS DOS TO IGNORE THE ERROR
  729.         IRET            ;THATS ALL WE DO HERE
  730. NEWINT24    ENDP
  731.  
  732. ;--------------------------------------------------------------------;
  733. ; HERE IS THE CODE USED TO INITIALIZE SNIPPER.                       ;
  734. ;--------------------------------------------------------------------;
  735.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  736. INITIALIZE:
  737.         LEA    DX,COPYRIGHT
  738.         MOV    AH,9        ;DOS DISPLAY STRING SERVICE
  739.         INT    21H        ;DISPLAY TITLE MESSAGE
  740. ; SEARCH FOR AN PREVIOUSLY INSTALLED COPY OF SNIPPER
  741.         NOT    BYTE PTR START    ;MODIFY TO AVOID FASLE MATCH
  742.         XOR    BX,BX        ;START SEARCH AT SEGMENT ZERO
  743.         MOV    AX,CS        ;COMPARE TO THIS CODE SEGMENT
  744. NEXT_SEGMENT:
  745.         INC    BX        ;LOOK AT NEXT SEGMENT
  746.         CMP    AX,BX        ;UNTIL REACHING THIS CODE SEG
  747.         MOV    ES,BX
  748.         JE    NOT_INSTALLED
  749.         LEA    SI,START    ;SETUP TO COMPARE STRINGS
  750.         MOV    DI,SI
  751.         MOV    CX,16        ;16 BYTES MUST MATCH
  752.         REP    CMPSB        ;COMPARE DS:SI TO ES:DI
  753.         OR    CX,CX        ;DID THE STRINGS MATCH?
  754.         JNZ    NEXT_SEGMENT    ;IF NO MATCH, TRY NEXT SEGMENT
  755.         LEA    DX,INSTALLED_MSG
  756.         JMP    SHORT ERR_EXIT
  757. NOT_INSTALLED:
  758.         MOV    AH,30H
  759.         INT    21H        ;GET DOS VERSION NUMBER
  760.         CMP    AL,2        ;IS IT HIGHER THAN 2.0?
  761.         JAE    VER_OK        ;IF YES, PROCEED
  762.         LEA    DX,BAD_DOS_MSG
  763. ERR_EXIT:    MOV    AH,9        ;DOS DISPLAY STRING SERVICE
  764.         INT    21H        ;DISPLAY ERRER MESSAGE
  765.         RET            ;RETURN TO DOS
  766. VER_OK:
  767.         INC    SI        ;POINT TO FIRST PARAMETER
  768.         MOV    SI,81H        ;POINT TO PARAMETER AREA
  769.         CALL    GET_PARAM    ;GET FIRST PARAMETER (ROWS)
  770.         PUSH    AX        ;SAVE THE ROW COUNT
  771.         CALL    GET_PARAM    ;GET SECOND PARAMETER (COLUMNS)
  772.         ADD    AX,2        ;ADD SPACE FOR CR AND LF
  773.         POP    BX        ;GET BACK FIRST PARAMETER
  774.         MUL    BX        ;PRODUCT OF ROWS AND COLUMNS
  775.         OR    AX,AX        ;WAS ANYTHING ENTERED?
  776.         JZ    NO_PARAMS    ;IF NOT, USE DEFAULT VALUE
  777.         CMP    AX,10000    ;MAXIMUM BUFFER IS 10000 BYTES
  778.         JLE    SIZE_IS_OK
  779.         MOV    AX,10000
  780. SIZE_IS_OK:
  781.         ADD    AX,BUFF_START
  782.         MOV    BUFF_END,AX    ;SET THE NEW BUFFER SIZE
  783. NO_PARAMS:
  784.         ASSUME    ES:NOTHING
  785.                MOV    AX,3509H    ;GET KEYBOARD BREAK VECTOR
  786.         INT    21H
  787.         MOV    WORD PTR [OLDINT09],  BX  ;SAVE SEGMENT
  788.         MOV    WORD PTR [OLDINT09+2],ES  ;SAVE OFFSET
  789.         MOV    DX, OFFSET NEWINT09
  790.         MOV    AX, 2509H
  791.         INT    21H        ;DOS FUNCTION TO CHANGE VECTOR
  792.  
  793.                MOV    AX,3513H    ;GET BIOS DISK INTERRUPT VECTOR
  794.         INT    21H
  795.         MOV    WORD PTR [OLDINT13],  BX  ;SAVE SEGMENT
  796.         MOV    WORD PTR [OLDINT13+2],ES  ;SAVE OFFSET
  797.         MOV    DX, OFFSET NEWINT13
  798.         MOV    AX, 2513H
  799.         INT    21H        ;DOS FUNCTION TO CHANGE VECTOR
  800.  
  801.                MOV    AX,3516H    ;GET KEYBOARD INPUT VECTOR
  802.         INT    21H
  803.         MOV    WORD PTR [OLDINT16],  BX  ;SAVE SEGMENT
  804.         MOV    WORD PTR [OLDINT16+2],ES  ;SAVE OFFSET
  805.         MOV    DX, OFFSET NEWINT16
  806.         MOV    AX, 2516H
  807.         INT    21H        ;DOS FUNCTION TO CHANGE VECTOR
  808.  
  809.                MOV    AX,3521H    ;GET DOS FUNCTION VECTOR
  810.         INT    21H
  811.         MOV    WORD PTR [OLDINT21],  BX
  812.         MOV    WORD PTR [OLDINT21+2],ES
  813.         MOV    DX, OFFSET NEWINT21
  814.         MOV    AX, 2521H
  815.         INT    21H        ;DOS FUNCTION TO CHANGE VECTOR
  816.  
  817. ;--------------------------------------------------------------------;
  818. ; DEALLOCATE OUR COPY OF THE ENVIORNMENT.                            ;
  819. ; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR BUFFER RESIDENT.      ;
  820. ;--------------------------------------------------------------------;
  821.  
  822.         MOV    AX,DS:[002CH]    ;GET SEGMENT OF ENVIORNMENT
  823.         MOV    ES,AX        ;PUT IT INTO ES
  824.         MOV    AH,49H        ;RELEASE ALLOCATED MEMORY
  825.         INT    21H
  826.         MOV    DX,BUFF_END    ;LEAVE THIS MUCH RESIDENT
  827.         INT    27H        ;TEMINATE AND STAY RESIDENT
  828. ;---------------------------------------------------------;
  829. ; GET_PARAM RETRIEVES AN INTEGER FROM THE COMMAND LINE.   ;
  830. ;---------------------------------------------------------;
  831. GET_PARAM:    XOR    AX,AX        ;CLEAR AX FOR TOTAL
  832. GET_DIGIT:    MOV    BL,[SI]        ;GET CHARACTER INTO BL
  833.         CMP    BL,0DH        ;IS IT THE LAST ONE?
  834.         JE    DONE
  835.         INC    SI        ;POINT TO NEXT CHARACTER
  836.         CMP    BL,","        ;IS IT THE DELIMITER?
  837.         JE    DONE
  838.         SUB    BL,30H        ;CONVERT ASCII TO INTEGER
  839.         JC    GET_DIGIT    ;IS IT A VALID DIGIT
  840.         CMP    BL,9
  841.         JA    GET_DIGIT    ;IF NOT VALID, JUST SKIP IT
  842.         MOV    BH,10        ;TIMES 10 FOR NEXT DIGIT
  843.         MUL    BH        ;MULTIPLY SUM AND ADD THIS DIGIT
  844.         ADD    AL,BL        ;ADD DIGIT TO SUM
  845.         JMP    GET_DIGIT    ;READ ALL CHARACTERS ON LINE
  846. DONE:        RET
  847. CSEG        ENDS
  848.         END    START
  849.